package br.ufpe.cin.msc.jrsj2.recommender;

import java.util.ArrayList;
import java.util.List;

import org.restlet.resource.Post;
import org.restlet.resource.ServerResource;

import br.ufpe.cin.msc.jrsj2.recommender.algorithm.Recommender;
import br.ufpe.cin.msc.jrsj2.recommender.dto.ProfileDTO;
import br.ufpe.cin.msc.jrsj2.recommender.message.ApplicationMessage;
import br.ufpe.cin.msc.jrsj2.recommender.message.ChannelMessage;
import br.ufpe.cin.msc.jrsj2.recommender.message.ClientMessage;
import br.ufpe.cin.msc.jrsj2.recommender.message.ClientProfileMessage;
import br.ufpe.cin.msc.jrsj2.recommender.message.Message;
import br.ufpe.cin.msc.jrsj2.recommender.message.ProfileMessage;
import br.ufpe.cin.msc.jrsj2.recommender.message.ProgramMessage;
import br.ufpe.cin.msc.jrsj2.recommender.ontology.OntologyServiceHandler;
import br.ufpe.cin.msc.jrsj2.recommender.persistence.dao.ChannelDAO;
import br.ufpe.cin.msc.jrsj2.recommender.persistence.dao.ClientDAO;
import br.ufpe.cin.msc.jrsj2.recommender.persistence.dao.DAOFactory;
import br.ufpe.cin.msc.jrsj2.recommender.persistence.dao.ProfileDAO;
import br.ufpe.cin.msc.jrsj2.recommender.persistence.dao.ProgramDAO;
import br.ufpe.cin.msc.jrsj2.recommender.persistence.domain.Channel;
import br.ufpe.cin.msc.jrsj2.recommender.persistence.domain.Client;
import br.ufpe.cin.msc.jrsj2.recommender.persistence.domain.Profile;
import br.ufpe.cin.msc.jrsj2.recommender.persistence.domain.Program;
import br.ufpe.cin.msc.jrsj2.recommender.util.ChannelFilter;
import br.ufpe.cin.msc.jrsj2.recommender.util.ClientHash;

public class RecommenderService extends ServerResource {

	private ChannelDAO channelDAO;
	private ProgramDAO programDAO;
	private ClientDAO clientDAO;
	private ProfileDAO profileDAO;

	public RecommenderService() {
		channelDAO = DAOFactory.getDAOFactory().getChannelDAO();
		programDAO = DAOFactory.getDAOFactory().getProgramDAO();
		clientDAO = DAOFactory.getDAOFactory().getClientDAO();
		profileDAO = DAOFactory.getDAOFactory().getProfileDAO();
	}

	@Post
	public String requestHandler(String message) {
		Bootstrap.exec();

		ApplicationMessage.setRequestMessage(message);

		System.out.println("Request: " + message);

		switch (Message.getMessageType(message)) {
		case CHANNEL:
			ChannelMessage channelMessage = new ChannelMessage();
			channelMessage.parseRequestMessage();

			switch (channelMessage.getChannelMessageType()) {
			case CREATE_CHANNEL:
				if (channelDAO.findByName(channelMessage.getChannelName()) != null) {
					ApplicationMessage.setResponseMessage("Channel "
							+ channelMessage.getChannelName()
							+ " already exists.");
				} else {
					Channel channel = new Channel(
							channelMessage.getChannelName(),
							channelMessage.getResource());

					channelDAO.create(channel);
					ApplicationMessage.setResponseMessage("Channel "
							+ channel.getName() + " created.");
				}
				break;
			case DELETE_CHANNEL:
				channelDAO.removeByName(channelMessage.getChannelName());
				ChannelMessage.setResponseMessage("Channel deleted.");
				break;
			case LIST_CHANNEL:
				channelMessage.buildResponseMessage(channelDAO.loadAll());
				break;
			}
			break;
		case PROGRAM:
			ProgramMessage programMessage = new ProgramMessage();
			programMessage.parseRequestMessage();

			switch (programMessage.getProgramMessageAction()) {
			case LIST_PROGRAM_BY_CHANNEL:
				Channel channel = channelDAO.findByName(programMessage
						.getChannelName());

				if (channel == null) {
					ApplicationMessage.setResponseMessage("Channel `"
							+ programMessage.getChannelName() + "' not found.");
					break;
				}

				programMessage.buildResponseMessage(programDAO
						.loadByChannel(channel));
				break;
			case LIST_PROGRAM:
				programMessage.buildResponseMessage(programDAO.loadAll());
			}
			break;
		case CLIENT:
			ClientMessage clientMessage = new ClientMessage();
			clientMessage.parseRequestMessage();

			switch (clientMessage.getClientMessageAction()) {
			case CREATE_CLIENT:
				if (clientDAO.findByHash(clientMessage.getHash()) != null) {
					ApplicationMessage.setResponseMessage("Client "
							+ clientMessage.getHash() + " already exists.");
				} else {
					Client client = new Client(clientMessage.getHash());

					clientDAO.create(client);
					ApplicationMessage.setResponseMessage("Client "
							+ client.getHash() + " created.");
				}
				break;
			case DELETE_CLIENT:
				clientDAO.removeByHash(clientMessage.getHash());
				ApplicationMessage.setResponseMessage("Client deleted.");
				break;
			case LIST_CLIENT:
				clientMessage.buildResponseMessage(clientDAO.loadAll());
				break;
			}
			break;
		case PROFILE:
			ProfileMessage profileMessage = new ProfileMessage();
			profileMessage.parseRequestMessage();

			switch (profileMessage.getProfileMessageAction()) {
			case CREATE_PROFILE:
				Program program = programDAO.findByTitle(profileMessage
						.getProgramTitle());
				Client client = clientDAO.findByHash(profileMessage
						.getClientHash());
				float rating = profileMessage.getRating();

				profileDAO.create(new Profile(program, client, rating));
				ApplicationMessage.setResponseMessage("Profile created.");
				break;
			case DELETE_PROFILE:
				break;
			case LIST_PROFILE:
				profileMessage.buildResponseMessage(profileDAO.loadAll());
				break;
			}
			break;
		case CLIENT_PROFILE:
			try {
				ClientProfileMessage clientProfileMessage = new ClientProfileMessage();

				clientProfileMessage.parseRequestMessage();

				List<Program> EPGProgramList = getEPGProgramList(clientProfileMessage);
				List<Profile> profileList = getClientProfileList(clientProfileMessage);
				List<Program> blackList = getBlackList(clientProfileMessage);
				Program currentProgram = getCurrentProgram(clientProfileMessage);

				this.removeFromBlackList(clientProfileMessage, EPGProgramList);
				EPGProgramList.remove(currentProgram);

				Recommender recommender = new Recommender(currentProgram,
						clientProfileMessage.getLength());
				List<Program> recommendations = recommender.getRecommendations(
						EPGProgramList, profileList, blackList);
				List<String> genres = new ArrayList<String>();
				String response = "";

				for (int i = 0; i < recommendations.size(); i++) {
					if (!genres.contains(recommendations.get(i).getGenre())) {
						response += "$" + recommendations.get(i).getGenre();
						response += ";";
						genres.add(recommendations.get(i).getGenre());
					}
					// response +=
					// recommendations.get(i).getChannel().getName();
					// response += ";";
					response += recommendations.get(i).getTitle();
					if (i != recommendations.size() - 1)
						response += ";";
				}

				ApplicationMessage.setResponseMessage(recommender.getResults().toString());
			} catch (Exception e) {
				e.printStackTrace();
				ApplicationMessage.setResponseMessage(e.getMessage());
			}
			break;
		case UNDEFINED:
			break;
		}

		System.out.println("Response: "
				+ ApplicationMessage.getResponseMessage());
		return ApplicationMessage.getResponseMessage();
	}

	private List<Program> getEPGProgramList(ClientProfileMessage message) {
		List<Program> EPGProgramList = new ArrayList<Program>();
		List<Channel> allChannels = channelDAO.loadAll();

		for (String programTitle : message.getAvailableProgramList()) {
			Program program = programDAO.findByTitle(programTitle);

			if (program == null) {
				program = OntologyServiceHandler
						.findOntologyInstanceForProgram(allChannels,
								programTitle);
				if (program != null)
					programDAO.create(program);
			}
			if (program != null)
				EPGProgramList.add(program);
		}

		return EPGProgramList;
	}

	private List<Program> getBlackList(ClientProfileMessage message) {
		List<Program> blackList = new ArrayList<Program>();
		List<Channel> allChannels = channelDAO.loadAll();

		for (String programTitle : message.getProgramBlackList()) {
			Program program = programDAO.findByTitle(programTitle);

			if (program == null) {
				program = OntologyServiceHandler
						.findOntologyInstanceForProgram(allChannels,
								programTitle);
				if (program != null)
					programDAO.create(program);
			}
			if (program != null)
				blackList.add(program);
		}

		return blackList;
	}

	private List<Profile> getClientProfileList(ClientProfileMessage message) {
		String clientHash = ClientHash.getClientHashString(message
				.getClientId());
		Client activeClient = clientDAO.findByHash(clientHash);

		if (activeClient == null) {
			activeClient = new Client(clientHash);
			activeClient = clientDAO.create(activeClient);
		}

		for (ProfileDTO entry : message.getPreferredProgramList()) {
			Channel channel = channelDAO.findByName(entry.getChannel());
			if (channel == null) {
				channel = channelDAO.findByName(ChannelFilter
						.replaceChannel(message.getCurrentChannelName()));
				if (channel == null) {
					ApplicationMessage.setResponseMessage("Channel `"
							+ entry.getChannel() + "' not found.");
					continue;
				}
			}

			Program program = programDAO.findByTitle(entry.getProgram());
			if (program == null) {
				program = OntologyServiceHandler.getOntologyInstanceForProgram(
						channel, entry.getProgram());
				if (program != null) {
					program.setChannel(channel);
					programDAO.create(program);
				}
			}
			if (program != null)
				profileDAO.create(new Profile(program, activeClient, entry
						.getRating()));
		}

		return profileDAO.findProfileByClient(activeClient);
	}

	private Program getCurrentProgram(ClientProfileMessage message) {
		Channel channel = channelDAO
				.findByName(message.getCurrentChannelName());
		Program program = programDAO.findByTitle(message
				.getCurrentProgramTitle());

		if (program == null) {
			program = OntologyServiceHandler.getOntologyInstanceForProgram(
					channel, message.getCurrentProgramTitle());
			if (program != null) {
				program.setChannel(channel);
				programDAO.create(program);
			}
		}

		return program;
	}

	private void removeFromBlackList(ClientProfileMessage message,
			List<Program> epg) {
		for (int i = 0; i < epg.size(); i++)
			for (int j = 0; j < message.getProgramBlackList().size(); j++)
				if (epg.get(i).getTitle()
						.equals(message.getProgramBlackList().get(j)))
					epg.remove(i);
		for (int i = 0; i < epg.size(); i++)
			for (int j = 0; j < message.getGenreBlackList().size(); j++)
				if (epg.get(i).getTitle()
						.equals(message.getGenreBlackList().get(j)))
					epg.remove(i);
	}

}
